﻿using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace UIOC.CodeAnalysis.Extensions;

internal static class TypeSymbolExtensions {

    /// <summary>
    /// 检查类型是否实现了指定接口
    /// </summary>
    public static bool ContainsInterface(this ITypeSymbol typeSymbol, ITypeSymbol interfaceTypeSymbol) {
        if (typeSymbol == null || interfaceTypeSymbol == null) {
            return false;
        }
        foreach (var baseInterfaceTypeSymbol in typeSymbol.AllInterfaces) {
            if (SymbolEqualityComparer.Default.Equals(baseInterfaceTypeSymbol, interfaceTypeSymbol)) {
                return true;
            }
            if (interfaceTypeSymbol is INamedTypeSymbol interfaceNamedTypeSymbol
                && interfaceNamedTypeSymbol.IsUnboundGenericType
                && baseInterfaceTypeSymbol.IsGenericType
            ) {
                if (IsGenericInstanceOf(baseInterfaceTypeSymbol, interfaceTypeSymbol)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static bool ContainsInterface(this ITypeSymbol typeSymbol, HashSet<ITypeSymbol> interfaceTypeSymbolSet) {
        if (typeSymbol == null || interfaceTypeSymbolSet == null)
            return false;
        foreach (var baseInterfaceTypeSymbol in typeSymbol.AllInterfaces) {
            if (interfaceTypeSymbolSet.Any(@interface => SymbolEqualityComparer.Default.Equals(baseInterfaceTypeSymbol, @interface))) {
                return true;
            }
            if (interfaceTypeSymbolSet is INamedTypeSymbol interfaceNamedTypeSymbol
                && interfaceNamedTypeSymbol.IsUnboundGenericType
                && baseInterfaceTypeSymbol.IsGenericType
            ) {
                if (interfaceTypeSymbolSet.Any(@interface => IsGenericInstanceOf(baseInterfaceTypeSymbol, @interface))) {
                    return true;
                }
            }
        }
        return false;
    }

    public static IEnumerable<AttributeData> GetAllAttributes(this ITypeSymbol typeSymbol, INamedTypeSymbol attributeSymbol) {
        while (typeSymbol != null) {
            foreach (var attr in typeSymbol.GetAttributes().Where(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeSymbol))) {
                yield return attr;
            }
            typeSymbol = typeSymbol.BaseType;
        }
    }

    /// <summary>
    /// 获取单个类型参数的名称（处理嵌套泛型）
    /// </summary>
    public static string GetTypeArgumentName(this ITypeSymbol typeSymbol) {
        // 如果是泛型类型（如 List<string>），递归处理
        if (typeSymbol is INamedTypeSymbol namedTypeSymbol && (namedTypeSymbol.IsGenericType || namedTypeSymbol.IsUnboundGenericType)) {
            return namedTypeSymbol.GetShortName();
        }

        // 普通类型直接返回名称（如 int、T）
        return typeSymbol.Name;
    }

    /// <summary>
    /// 获取类型参数的短名称（支持嵌套泛型）
    /// </summary>
    public static string GetTypeArgumentShortName(this ITypeSymbol typeSymbol) {
        // 如果是命名类型（类、接口等）
        if (typeSymbol is INamedTypeSymbol namedType) {
            return namedType.GetShortName();
        }

        // 处理数组类型（如 T[]、int[]）
        if (typeSymbol is IArrayTypeSymbol arrayType) {
            return $"{GetTypeArgumentShortName(arrayType.ElementType)}[]";
        }

        // 处理指针类型（如 T*）
        if (typeSymbol is IPointerTypeSymbol pointerType) {
            return $"{GetTypeArgumentShortName(pointerType.PointedAtType)}*";
        }

        // 处理其他类型（如基本类型、类型参数、nullable等）
        return typeSymbol.Name;
    }

    /// <summary>
    /// 判断泛型实例（如IData<T>）是否是目标泛型定义（如IData<>）的实例
    /// </summary>
    private static bool IsGenericInstanceOf(INamedTypeSymbol baseInterfaceTypeSymbol, ITypeSymbol interfaceTypeSymbol) {
        // 前提：目标是未绑定泛型，当前是已绑定泛型
        if (interfaceTypeSymbol is not INamedTypeSymbol interfaceNamedTypeSymbol || !interfaceNamedTypeSymbol.IsUnboundGenericType || !baseInterfaceTypeSymbol.IsGenericType)
            return false;

        // 核心判断：命名空间、基础名称、泛型参数数量完全一致
        return AreNamespacesEqual(baseInterfaceTypeSymbol, interfaceNamedTypeSymbol) &&
               GetBaseName(baseInterfaceTypeSymbol) == GetBaseName(interfaceNamedTypeSymbol) &&
               baseInterfaceTypeSymbol.Arity == interfaceNamedTypeSymbol.Arity;
    }

    /// <summary>
    /// 获取类型的基础名称（不含泛型参数标记，如"IData"）
    /// </summary>
    private static string GetBaseName(ITypeSymbol typeSymbol) {
        // 泛型类型的元数据名称格式为"IData`1"（`1表示1个泛型参数），截取`之前的部分
        string metadataName = typeSymbol.MetadataName;
        int backtickIndex = metadataName.IndexOf('`');
        return backtickIndex > 0 ? metadataName.Substring(0, backtickIndex) : metadataName;
    }

    /// <summary>
    /// 比较两个类型的命名空间是否相等
    /// </summary>
    private static bool AreNamespacesEqual(ITypeSymbol a, ITypeSymbol b) {
        return SymbolEqualityComparer.Default.Equals(a.ContainingNamespace, b.ContainingNamespace);
    }

    public static List<SyntaxReference> GetUserSyntaxReferences(this ITypeSymbol typeSymbol) {
        if (typeSymbol == null)
            return null;

        // 1. 获取类定义所在的语法引用（源代码位置）
        // 注意：部分类可能有多个定义位置，需检查所有位置
        var syntaxReferences = typeSymbol.DeclaringSyntaxReferences;
        if (syntaxReferences.Length == 0)
            return null;

        var resultList = new List<SyntaxReference>();
        // 2. 检查每个定义位置的源代码文件是否包含自动生成标记
        foreach (var syntaxRef in syntaxReferences) {
            // 获取语法树（包含源代码）
            var syntaxTree = syntaxRef.SyntaxTree;
            if (syntaxTree == null)
                continue;

            // 3. 检查文件是否包含自动生成标记（如 <auto-generated> 注释）
            if (!IsGeneratedFile(syntaxTree)) {
                resultList.Add(syntaxRef);
            }
        }

        return resultList;
    }

    /// <summary>
    /// 判断语法树（源代码文件）是否为自动生成的文件
    /// </summary>
    private static bool IsGeneratedFile(SyntaxTree syntaxTree) {
        // 读取文件头部注释（自动生成标记通常在文件开头）
        var root = syntaxTree.GetRoot();
        var firstToken = root.GetFirstToken();
        if (!firstToken.HasLeadingTrivia)
            return false;

        // 检查是否包含自动生成标记（支持常见格式）
        var leadingTrivia = firstToken.LeadingTrivia.ToString();
        return leadingTrivia.Contains("<auto-generated>") ||  // 标准自动生成标记
               leadingTrivia.Contains("This file was automatically generated") ||  // 常见生成提示
               leadingTrivia.Contains("Auto-generated by");  // 生成工具标识
    }

    /// <summary>
    /// 从接口类型符号获取对应类名（保留泛型参数结构）
    /// 示例：IGlobalInterface&lt;T&gt; → GlobalInterface&lt;T&gt;，IRepository&lt;T1,T2&gt; → Repository&lt;T1,T2&gt;
    /// </summary>
    /// <param name="interfaceSymbol">接口类型符号</param>
    /// <returns>对应类名（保留泛型参数）</returns>
    public static string GetClassNameFromInterface(this ITypeSymbol interfaceSymbol) {

        // 基础校验：必须是接口类型
        if (interfaceSymbol?.TypeKind != TypeKind.Interface)
            return null;

        // 1. 获取接口名称（不含泛型参数部分）
        var interfaceName = interfaceSymbol.Name;
        var genericMarkerIndex = interfaceName.IndexOf('`');
        if (genericMarkerIndex > 0) {
            interfaceName = interfaceName.Substring(0, genericMarkerIndex);
        }

        // 2. 移除开头的 'I'（如果存在）
        var className = interfaceName.StartsWith("I") && interfaceName.Length > 1 ? interfaceName.Substring(1) : interfaceName;

        // 3. 处理泛型参数（保留原泛型参数结构）
        if (interfaceSymbol is INamedTypeSymbol namedType && namedType.IsGenericType) {
            // 获取泛型参数列表（如 T → T，TEntity → TEntity）
            var typeArguments = namedType.TypeArguments
                .Select(arg => arg.Name) // 取参数名（如 T、TEntity）
                .ToList();

            // 拼接泛型类名（如 Repository<TEntity, TKey>）
            return $"{className}<{string.Join(", ", typeArguments)}>";
        }

        // 非泛型接口直接返回类名
        return className;
    }

    public static SimpleBaseTypeSyntax CreateSimpleBaseTypeSyntax(this ITypeSymbol typeSymbol, TypeArgumentListSyntax typeArgumentListSyntaxes = null) {
        return SyntaxFactory.SimpleBaseType(typeSymbol.CreateSimpleNameSyntax(typeArgumentListSyntaxes));
    }

    public static SimpleNameSyntax CreateSimpleNameSyntax(this ITypeSymbol typeSymbol,
        TypeArgumentListSyntax typeArgumentListSyntaxes = null,
        bool IsUnboundGenericType = false, string suffix = null
    ) {
        if (typeSymbol is null) {
            return null;
        }
        if (typeSymbol is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGenericType) {
            // 处理泛型类型
            var nameSyntax = SyntaxFactory.GenericName(
                SyntaxFactory.Identifier(namedTypeSymbol.ToDisplayString(
                    new SymbolDisplayFormat(
                        globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
                        typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces
                    )
                ) + (string.IsNullOrEmpty(suffix) ? string.Empty : suffix))
            );
            typeArgumentListSyntaxes ??= SyntaxFactory.TypeArgumentList(
                SyntaxFactory.SeparatedList<TypeSyntax>(
                    namedTypeSymbol.TypeArguments.Select(arg => arg is INamedTypeSymbol argNamedTypeSymbol
                        ? IsUnboundGenericType ? SyntaxFactory.IdentifierName(string.Empty) : argNamedTypeSymbol.CreateSimpleNameSyntax()
                        : SyntaxFactory.IdentifierName(IsUnboundGenericType ? string.Empty : arg.Name)
                    )
                )
            );
            if (typeArgumentListSyntaxes?.Arguments.Any() != true) {
                return nameSyntax;
            }
            nameSyntax = nameSyntax.WithTypeArgumentList(typeArgumentListSyntaxes);
            return nameSyntax;
        } else {
            return SyntaxFactory.IdentifierName(typeSymbol.ToDisplayString(
                new SymbolDisplayFormat(
                    globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
                    typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces
                )
            ) + (string.IsNullOrEmpty(suffix) ? string.Empty : suffix));
        }
    }
}